package com.jintian.smart.kernel.autoconfigure.beetl;

import com.jintian.smart.kernel.common.util.StringUtil;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 通过EnableBeetlMapper注解扫描注册BeetlSql的Mapper。Ordered.LOWEST_PRECEDENCE最后执行。
 */
public class BeetlSqlMapperRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware, Ordered {
    ResourceLoader resourceLoader;
    Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        this.registerBeetlSqlBeanDefinitions(registry, metadata);
    }

    private void registerBeetlSqlBeanDefinitions(BeanDefinitionRegistry registry, AnnotationMetadata metadata) {
        // 1.获取或创建BeetlSqlProperties
        BeetlSqlProperties beetlSqlProperties = BeetlSqlBeanUtils.getOrCreateBeetlSqlProperties(registry, (ConfigurableEnvironment) environment);
        // 2.扫描注册Mapper
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(EnableBeetlMapper.class.getName()));
        this.registerBeetlSqlBeanDefinitions(registry, beetlSqlProperties, mapperScanAttrs, ClassUtils.getPackageName(metadata.getClassName()));
    }

    @SuppressWarnings("unchecked")
    protected void registerBeetlSqlBeanDefinitions(BeanDefinitionRegistry registry, BeetlSqlProperties beetlSqlProperties, AnnotationAttributes mapperScanAttrs, String entiryPackage) {
        Set<String> basePackages = new HashSet<>(Arrays.asList(mapperScanAttrs.getStringArray("basePackages")));
        String mapperSuffix = (String) mapperScanAttrs.getString("mapperSuffix");
        String sqlManagerName = (String) mapperScanAttrs.getString("sqlManager");
        if (StringUtil.isEmpty(sqlManagerName)) {
            sqlManagerName = beetlSqlProperties.sqlManagers.keySet().iterator().next();
        }
        if (basePackages.size() == 0 && entiryPackage != null) {
            basePackages.add(entiryPackage);
        }
        {
            BeetlSqlProperties.SQLManagerConfig config = beetlSqlProperties.getSqlManagers().get(sqlManagerName);
            if (config != null && config.getBasePackage() != null) {
                String[] exists = config.getBasePackage().split(",");
                Set<String> excludes = new HashSet<>();
                for (String name : exists) {
                    for (String p : basePackages) {
                        if (p.startsWith(name + ".") || p.equals(name)) {
                            excludes.add(p);
                        }
                    }
                }
                basePackages.removeAll(excludes);
            }
        }
        if (basePackages.size() > 0) {
            BeetlSqlMapperScan scan = BeetlSqlMapperScan.builder()
                    .basePackages(basePackages.toArray(new String[0]))
                    .mapperSuffix(mapperSuffix)
                    .sqlManager(sqlManagerName)
                    .include((Class<TypeFilter>[]) mapperScanAttrs.getClassArray("include"))
                    .exclude((Class<TypeFilter>[]) mapperScanAttrs.getClassArray("exclude")).build();

            BeetlSqlBeanUtils.scanMapper(registry, resourceLoader, scan);
        }
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    static class RepeatingRegistrar extends BeetlSqlMapperRegistrar {
        /**
         * {@inheritDoc}
         */
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            BeetlSqlProperties beetlSqlProperties = BeetlSqlBeanUtils.getOrCreateBeetlSqlProperties(registry, (ConfigurableEnvironment) environment);
            AnnotationAttributes mapperScansAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableBeetlMappers.class.getName()));
            if (mapperScansAttrs != null) {
                AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value");
                for (int i = 0; i < annotations.length; i++) {
                    this.registerBeetlSqlBeanDefinitions(registry, beetlSqlProperties, annotations[i], null);
                }
            }
        }
    }
}
